今天的程式都在這個commit上
簡單來說就兩支API
下面的程式有到用gjson這套件
它可以用key直接取json的值,不用寫一個struct來json unmarshal。
config多加GoogleSecretKey、GoogleClientID
config/config.go
// Config Config
type Config struct {
Mode string `mapstructure:"MODE"`
Port string `mapstructure:"PORT"`
GoogleSecretKey string `mapstructure:"GOOGLE_SECRET_KEY"`
GoogleClientID string `mapstructure:"GOOLE_CLIENT_ID"`
}
config.yaml
GOOGLE_SECRET_KEY: "{{GOOGLE_SECRET_KEY}}"
GOOLE_CLIENT_ID: "{{GOOLE_CLIENT_ID}}"
多加兩支API
main.go
api := r.Group("/api")
{
api.GET("ouath/google/url", handler.GoogleAccsess)
api.GET("ouath/google/login", handler.GoogleLogin)
}
要使用者導向到OAuth同意頁面
https://accounts.google.com/o/oauth2/v2/auth
參數:
client_id=你的client id 上一篇申請的
redirect_uri=使用者同意後要導向那裡 (目前測試先導到本機http://localhost:9090/api/ouath/google/login)
scope=https://www.googleapis.com/auth/userinfo.profile (授權使用者資料)
response_type=code (authorization code 後面要拿它去打API用)
handler/auth.go
// GoogleAccsess GoogleAccsess
func GoogleAccsess(c *gin.Context) {
res.Success(c, gin.H{
"url": oauthURL(),
})
}
func oauthURL() string {
u := "https://accounts.google.com/o/oauth2/v2/auth?client_id=%s&response_type=code&scope=%s&redirect_uri=%s"
return fmt.Sprintf(u, config.Val.GoogleClientID, scope, redirectURL)
}
使用者同意後會導回
http://localhost:9090/api/ouath/google/login
Google導回來的時候,在url會多帶一個code給你
拿code去打這API,拿到token
https://www.googleapis.com/oauth2/v4/token
參數:
code=從url拿的
grant_type=authorization_code
client_id=你的client_id
client_secret=你的secret
redirect_uri=http://localhost:9090/api/ouath/google/login
拿到token,最後去取得會員資料
https://www.googleapis.com/oauth2/v1/userinfo?alt=json
參數:
access_token=token
// GoogleLogin GoogleLogin
func GoogleLogin(c *gin.Context) {
code := c.Query("code")
token, err := accessToken(code)
if err != nil {
log.WithFields(log.Fields{
"err": err,
}).Debug("accessToken error")
c.Redirect(http.StatusFound, "/")
return
}
id, name, err := getGoogleUserInfo(token)
if err != nil {
log.WithFields(log.Fields{
"err": err,
}).Debug("getGoogleUserInfo error")
c.Redirect(http.StatusFound, "/")
return
}
// 把值log出來看
log.Infof("id: %v, name: %v", id, name)
}
func accessToken(code string) (token string, err error) {
u := "https://www.googleapis.com/oauth2/v4/token"
data := url.Values{"code": {code}, "client_id": {config.Val.GoogleClientID}, "client_secret": {config.Val.GoogleSecretKey}, "grant_type": {"authorization_code"}, "redirect_uri": {redirectURL}}
body := strings.NewReader(data.Encode())
resp, err := http.Post(u, "application/x-www-form-urlencoded", body)
if err != nil {
return token, err
}
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return token, err
}
token = gjson.GetBytes(b, "access_token").String()
return token, nil
}
func getGoogleUserInfo(token string) (id, name string, err error) {
u := fmt.Sprintf("https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token=%s", token)
resp, err := http.Get(u)
if err != nil {
return id, name, err
}
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
return id, name, err
}
name = gjson.GetBytes(body, "name").String()
id = gjson.GetBytes(body, "id").String()
return id, name, nil
}
最後在Google console的已授權的重新導向URI加上我們的API
直接來操作一次
URL點下去
同意了之後目前會是空白頁,因為頁面還沒做。
這時候看一下terminal
成功了把會員的名稱跟ID都要回來
明天會把JWT Token也補上
今天先這樣! 謝謝大家